package com.zxq.uart.lock;

import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import com.zxq.uart.config.LockConfig;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;


/**
 * 为了异步读取数据
 */
@Slf4j
public class LockContainer {

    /**
     * 锁容器
     */
    static ConcurrentMap<String, Condition> channelLockContainer = new ConcurrentHashMap<>();

    /**
     * 数据容器
     */
    static ConcurrentMap<String, byte[]> channelDataContainer = new ConcurrentHashMap<>();


    /**
     * 独占锁
     */
    static ReentrantLock reentrantLock = new ReentrantLock();
    /**
     * 核心算法，这里是想让他异步把数据回传回来
     * 锁通道
     * @param devId 设备编号
     */
    public final static byte[] lockChannel(String devId) {
            reentrantLock.lock();
            Condition condition = reentrantLock.newCondition();
            channelLockContainer.put(devId, condition);
            try {
                condition.await(LockConfig.getTimeOut(), TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            byte[] msg = channelDataContainer.get(devId);
            log.info(" channel:" + devId + " rec:" + HexBin.encode(msg));
            channelLockContainer.remove(devId);
            channelDataContainer.remove(devId);
            reentrantLock.unlock();
            return msg;
    }

    /**
     * 是否包含该key
     * @param devId
     * @return
     */
    public static Boolean isLock(String devId) {
        return channelLockContainer.containsKey(devId);
    }


    /**
     * 通知通道解锁数据
     * @param devId 设备编号
     */
    public final static void notifyChannel(String devId, byte[] data) {
            log.info("rec devId:{} data:{}",devId, HexBin.encode(data));
            reentrantLock.lock();
            Condition condition = channelLockContainer.get(devId);
            if (condition == null) {
                log.info("condition null");
                return;
            }
            channelDataContainer.put(devId, data);
            condition.signal();
            reentrantLock.unlock();
    }


}
